﻿using Sasa.QualityTools.CodeAnalysis.Core.Entities;
using System;
using System.IO;
using System.Xml;

namespace Sasa.QualityTools.CodeAnalysis.Core.Repositories
{
    public class CodeAnalysisConfigurationRepository
    {
        private string path;


        public CodeAnalysisConfigurationRepository(string path)
        {
            this.path = path;
        }


        public void SaveConfiguration(CodeAnalysisConfiguration configuration)
        {
            using (var stream = new FileStream(path, FileMode.Truncate, FileAccess.Write, FileShare.Write))
            {
                SaveConfiguration(configuration, stream);
            }
        }

        internal void SaveConfiguration(CodeAnalysisConfiguration configuration, Stream stream)
        {
            var settings = new XmlWriterSettings();
            settings.Indent = true;
            using (var writer = XmlWriter.Create(stream, settings))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("CodeAnalysisConfiguration");
                WriteRoot(writer, configuration);
                WriteValue(writer, "EnableSearchGAC", configuration.OverrideEnableSearchGac, configuration.EnableSearchGac);
                WriteValue(writer, "IgnoreGeneratedCode", configuration.OverrideIgnoreGeneratedCode, configuration.IgnoreGeneratedCode);
                WriteValue(writer, "Timeout", configuration.OverrideTimeout, configuration.Timeout);
                WriteRuleSetValue(writer, configuration.OverrideRuleSet, configuration.RuleSet);
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }

        public CodeAnalysisConfiguration FindConfiguration()
        {
            if (!File.Exists(path)) return new CodeAnalysisConfiguration();

            using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                return FindConfiguration(stream);
            }
        }

        internal CodeAnalysisConfiguration FindConfiguration(Stream stream)
        {
            var configuration = new CodeAnalysisConfiguration();

            var settings = new XmlReaderSettings();
            settings.ConformanceLevel = ConformanceLevel.Document;
            settings.IgnoreWhitespace = true;
            using (var reader = XmlReader.Create(stream, settings))
            {
                reader.Read();
                reader.Read();
                if (reader.GetAttribute("Version") != "1.2.0")
                {
                    throw new NotSupportedException("Failed to deserialize a code analysis configuration because configuration file version is not supported by current extension.");
                }
                configuration.EnableCodeAnalysis = Convert.ToBoolean(reader.GetAttribute("Enable"));
                reader.ReadStartElement("CodeAnalysisConfiguration");

                configuration.OverrideEnableSearchGac = Convert.ToBoolean(reader.GetAttribute("Override"));
                configuration.EnableSearchGac = Convert.ToBoolean(reader.GetAttribute("Value"));
                reader.ReadStartElement("EnableSearchGAC");

                configuration.OverrideIgnoreGeneratedCode = Convert.ToBoolean(reader.GetAttribute("Override"));
                configuration.IgnoreGeneratedCode = Convert.ToBoolean(reader.GetAttribute("Value"));
                reader.ReadStartElement("IgnoreGeneratedCode");

                configuration.OverrideTimeout = Convert.ToBoolean(reader.GetAttribute("Override"));
                configuration.Timeout = Convert.ToDouble(reader.GetAttribute("Value"));
                reader.ReadStartElement("Timeout");

                configuration.OverrideRuleSet = Convert.ToBoolean(reader.GetAttribute("Override"));
                configuration.RuleSet = reader.GetAttribute("Value");
                reader.ReadStartElement("RuleSet");

                reader.ReadEndElement();
            }

            return configuration;
        }


        private void WriteRoot(XmlWriter writer, CodeAnalysisConfiguration configuration)
        {
            writer.WriteStartAttribute("Version");
            writer.WriteValue("1.2.0");
            writer.WriteEndAttribute();

            writer.WriteStartAttribute("Enable");
            writer.WriteValue(configuration.EnableCodeAnalysis);
            writer.WriteEndAttribute();
        }

        private void WriteValue(XmlWriter writer, string elementName, bool isOverride, object value)
        {
            writer.WriteStartElement(elementName);
            writer.WriteStartAttribute("Override");
            writer.WriteValue(isOverride);
            writer.WriteEndAttribute();
            writer.WriteStartAttribute("Value");
            writer.WriteValue(value ?? "");
            writer.WriteEndAttribute();
            writer.WriteEndElement();
        }

        private void WriteRuleSetValue(XmlWriter writer, bool isOverride, object value)
        {
            writer.WriteStartElement("RuleSet");
            writer.WriteStartAttribute("Override");
            writer.WriteValue(isOverride);
            writer.WriteEndAttribute();
            if (value != null)
            {
                writer.WriteStartAttribute("Value");
                writer.WriteValue(value ?? "");
                writer.WriteEndAttribute();
            }
            writer.WriteEndElement();
        }
    }
}
